using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using ShevaEngine.Core.Interfaces;

namespace ShevaEngine.Core.Modules.Input
{
    /// <summary>
    /// Keyboard class.
    /// </summary>
    public class ShevaKeyboard : IUpdateAble
    {
        /// <summary>Keyaboard previous state.</summary>
        private KeyboardState PreviousState;

        /// <summary>OnKeyDown event.</summary>
        public event OnKeyEventDelegate OnKeyDown;
        /// <summary>OnKeyUp event.</summary>
        public event OnKeyEventDelegate OnKeyUp;
        /// <summary>OnKeyPressed event.</summary>
        public event OnKeyEventDelegate OnKeyPressed;
        /// <summary>OnCharPressed event.</summary>
        public event OnCharEventDelegate OnCharPressed;

        /// <summary>
        /// Konstruktor.
        /// </summary>
        public ShevaKeyboard()
        {
            this.PreviousState = Keyboard.GetState();
        }

        /// <summary>
        /// Method Update().
        /// </summary>
        /// <param name="deltaT"></param>
        public void Update(GameTime time)
        {
            KeyboardState newState = Keyboard.GetState();            

            HashSet<Keys> previousPressedKeys = new HashSet<Keys>(this.PreviousState.GetPressedKeys());
            HashSet<Keys> newPressedKeys = new HashSet<Keys>(newState.GetPressedKeys());
            
            foreach (Keys key in newPressedKeys)
            {
                if (!previousPressedKeys.Contains(key))                
                {
                    if (this.OnKeyDown != null)
                        this.OnKeyDown(this, key);

                    previousPressedKeys.Remove(key);
                }
            }

            foreach (Keys key in previousPressedKeys)
            {
                if (!newPressedKeys.Contains(key))
                {
                    if (this.OnKeyUp != null)
                        this.OnKeyUp(this, key);

                    if (this.OnKeyPressed != null)
                        this.OnKeyPressed(this, key);

                    if ((Keys.A <= key && key <= Keys.Z) ||
                        (Keys.NumPad0 <= key && key <= Keys.NumPad9) ||
                        (Keys.D0 <= key && key <= Keys.D9))
                    {
                        char znak = (char)key;

                        if (!newState.IsKeyDown(Keys.LeftShift))
                            znak = Char.ToLower(znak);

                        if (this.OnCharPressed != null)
                            this.OnCharPressed(this, znak);
                    }
                }
            }

            this.PreviousState = newState;                       
        }        

        /// <summary>
        /// Method IsKeyDown().
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool IsKeyDown(Keys key)
        {
            return this.PreviousState.IsKeyDown(key);
        }
    }

    /// <summary>
    /// Delegat udalosti stisku klavesy.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void OnKeyEventDelegate(object sender, Keys e);

    /// <summary>
    /// Delegat udalosti stisku znaku.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="value"></param>
    public delegate void OnCharEventDelegate(object sender, char value);
}
